云原生 etcd 系列|为什么值得学习?
什么是 etcd ?
etcd 是 CoreOS 团队于 2013 年 6 月发起的开源项目。etcd 官网上有这么一段话:
A distributed, reliable key-value store for the most critical data of a distributed system
etcd 是一个分布式、高可靠的 kv 系统,基于 Go 语言实现,内部使用 raft 协议来保证数据一致性和高可靠性。
哦,就是一个 kv 系统哦,etcd 一般用来做什么呢?
对于 etcd 的定位其实在名字里亦可窥见,etcd 这个名字拆开来看就是 etc distributed ,也是就是分布式的 etc 嘛),大家都知道 linux 的 etc 目录就是单机的配置中心。所以 etcd 的应用定位其实就是分布式的配置中心系统嘛,目的就是为服务集群提供一个的全局性配置中心。
etcd 为什么值得学?
etcd 有两个重要项目为其背书:CoreOS,Kubernetes,有人甚至号称 etcd 是云原生的基石之一。
为什么会这么说?
因为 etcd 在其中扮演的角色太重要了,Kubernetes 把核心元数据信息存储在里面。
etcd 在非常多的互联网大厂里都有深度的应用,如果应聘一些云原生的岗位,对 etcd 的熟悉会是很好的亮点。
etcd 的数据一致性和高可靠是基于 raft 协议实现的。如果有童鞋对 raft 精通理论,但是苦于没有代码实践,这是一个非常好的学习 demo 。
etcd 对 raft 的封装那简直了,分层抽象的太厉害了。raft 模块几乎就只集中了状态机的实现,把 wal 啥的都抽出去了,在 raft 状态机中,对于日志的使用抽象出了 Storage 接口。
所以单就代码来说,真的值得学习一波。
etcd 的特点
简单:接口简单,使用简单; 安全:支持 TLS 证书认证; 强一致性:通过 raft 协议保证数据的强一致性,实现 leader 到 follower 节点的正确复制; 高可用性:集群能自动处理单点故障,网络分区等情况,对外提供高可靠、一致性的数据访问; 性能不错:看官网的 benchmark 数据是 10000 次每秒的写入;
其实经过了 k8s 等超大型的项目验证,etcd 已经是一个非常成熟的项目了。
怎么入手学习?
下面聊聊怎么去学习,这篇是开篇文章。
奇伢很早就拉了个仓库出来,用于阅读 etcd 的代码,版本是 v3.4.10 。
https://github.com/liqingqiya/readcode-etcd-v3.4.10
一直在不断的在这个仓库里加注释,该仓库代码可直接编译,建议 Go 版本 >= 1.14 。
etcd 说白了就是是 kv 存储,只不过这个 kv 存储是分布式的,数据是多副本冗余的,kv 是有多版本功能的。
既然是多节点那最重要的是一致性,etcd 使用了 raft 算法解决了数据多节点的一致性。
说起来 etcd 也是个不小的项目,要撸开源项目最好的就是找到一个切入点,从一个很小的点开始,慢慢往外延伸。etcd 考虑到这点,提供了一个非常好的演示项目 raftexample 。
这个模块旨在通过一个极简的例子帮助大家理解 raft 模块在 etcd 中的使用姿势。理解 raft 的模块对理解 etcd 整体流程有非常大的帮助。
所以,第一步就是去撸一遍 raft 相关的代码,etcd 的业务从抽象模块来讲运行在 raft 模块,只要把 raft 相关模块理解了,etcd 就算理解 50 % ,剩下的基本都是业务功能。
raftexample 的目录位于 etcd/contrib/raftexample/ ,这个目录是一个完整的 package,实现了一个极简的 kv 存储,就是为了专门理解 raft 的。
➜ raftexample git:(master) ✗ tree -L 1
.
├── httpapi.go # 最上层的模块,对外提供 http api,我们命名为 api 层;
├── kvstore.go # kv 存储的实现,业务层的实现,我们命名为 service 层;
├── raft.go # 承上启下的模块,对上对接 service 模块,对下对接 raft 状态机模块;
├── listener.go # 和 raftNode 是一起的;
├── main.go # 入口文件
0 directories, 10 files
具体的模块划分为四层:
下一步,开始编译。
克隆仓库下来:
git clone https://github.com/liqingqiya/readcode-etcd-v3.4.10.git
编译(可以把一些依赖包下载下来):
root@ubuntu:~/code/github/readcode-etcd-v3.4.10/src/go.etcd.io/etcd# make
....
go.etcd.io/etcd/etcdctl
./bin/etcd --version
etcd Version: 3.4.10
Git SHA: b516720
Go Version: go1.14.4
Go OS/Arch: linux/amd64
./bin/etcdctl version
etcdctl version: 3.4.10
API version: 3.4
这样需要的一些依赖包自动就下载下来了。然后,我们就去编译 raftexample 这个程序。
root@ubuntu:~/code/github/readcode-etcd-v3.4.10/src/go.etcd.io/etcd/contrib/raftexample# go build -gcflags=all="-N -l"
编译出 raftexample
的二进制就代表成功了,具有了学习的素材。按照 README 的提示,我们用 goreman 来启动程序:
goreman start
goreman
读的是当前目录的 Procfile 文件,这个文件是这样写的:
root@ubuntu:~/code/github/readcode-etcd-v3.4.10/src/go.etcd.io/etcd/contrib/raftexample# cat Procfile
# Use goreman to run `go get github.com/mattn/goreman`
raftexample1: ./raftexample --id 1 --cluster http://127.0.0.1:12379,http://127.0.0.1:22379,http://127.0.0.1:32379 --port 12380
raftexample2: ./raftexample --id 2 --cluster http://127.0.0.1:12379,http://127.0.0.1:22379,http://127.0.0.1:32379 --port 22380
raftexample3: ./raftexample --id 3 --cluster http://127.0.0.1:12379,http://127.0.0.1:22379,http://127.0.0.1:32379 --port 32380
也就是启动 3 个 raftexample 进程,分别使用了不同的端口,这样就省去了我们人为的键入,方便一些。
goreman start
执行,你就会发现拉起了 3 个进程,这组成了一个最简单的 raft 集群。
接下来,我们就调试+阅读这个程序的代码,来理解 raft 是怎么回事。
奇伢梳理了一系列 etcd 的深度剖析文章,以后整理出来分享,先抛出一张 raftexample 模块图,用于描述 raftexample 业务层 -> raftNode -> raft 状态机 这三层的交互关系,它们之间多通过 channel 进行交互:
后记
~完~
往期推荐
往期推荐
坚持思考,方向比努力更重要。关注我:奇伢云存储。
欢迎加我好友,技术交流。